void eth_mac_irq()
{
    /* Service MAC IRQ here */

    /* Allocate pbuf from pool (avoid using heap in interrupts) */
    struct pbuf *p = pbuf_alloc(PBUF_RAW, eth_data_count, PBUF_POOL);

    if(p != NULL)
    {
        /* Copy ethernet frame into pbuf */
        pbuf_take(p, eth_data, eth_data_count);

        /* Put in a queue which is processed in main loop */
        if(!queue_try_put(&queue, p))
        {
            /* queue is full -> packet loss */
            pbuf_free(p);
        }
    }
}

static err_t netif_output(struct netif *netif, struct pbuf *p)
{
    LINK_STATS_INC(link.xmit);

    /* Update SNMP stats (only if you use SNMP) */
    MIB2_STATS_NETIF_ADD(netif, ifoutoctets, p->tot_len);
    int unicast = ((p->payload[0] & 0x01) == 0);
    if (unicast)
    {
        MIB2_STATS_NETIF_INC(netif, ifoutucastpkts);
    }
    else
    {
        MIB2_STATS_NETIF_INC(netif, ifoutnucastpkts);
    }

    lock_interrupts();
    pbuf_copy_partial(p, mac_send_buffer, p->tot_len, 0);
    /* Start MAC transmit here */
    unlock_interrupts();

    return ERR_OK;
}

static void netif_status_callback(struct netif *netif)
{
    printf("netif status changed %s\n", ip4addr_ntoa(netif_ip4_addr(netif)));
}

static err_t netif_init(struct netif *netif)
{
    netif->linkoutput = netif_output;
    netif->output     = etharp_output;
    netif->output_ip6 = ethip6_output;
    netif->mtu        = ETHERNET_MTU;
    netif->flags      = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET | NETIF_FLAG_IGMP | NETIF_FLAG_MLD6;
    MIB2_INIT_NETIF(netif, snmp_ifType_ethernet_csmacd, 100000000);

    SMEMCPY(netif->hwaddr, your_mac_address_goes_here, sizeof(netif->hwaddr));
    netif->hwaddr_len = sizeof(netif->hwaddr);

    return ERR_OK;
}

void main(void)
{
    struct netif netif;

    lwip_init();

    netif_add(&netif, IP4_ADDR_ANY, IP4_ADDR_ANY, IP4_ADDR_ANY, NULL, netif_init, netif_input);
    netif.name[0] = 'e';
    netif.name[1] = '0';
    netif_create_ip6_linklocal_address(&netif, 1);
    netif.ip6_autoconfig_enabled = 1;
    netif_set_status_callback(&netif, netif_status_callback);
    netif_set_default(&netif);
    netif_set_up(&netif);

    /* Start DHCP and HTTPD */
    dhcp_init();
    httpd_init();

    while(1)
    {
        /* Check link state, e.g. via MDIO communication with PHY */
        if(link_state_changed())
        {
            if(link_is_up())
            {
                netif_set_link_up(&netif);
            }
            else
            {
                netif_set_link_down(&netif);
            }
        }

        /* Check for received frames, feed them to lwIP */
        lock_interrupts();
        struct pbuf *p = queue_try_get(&queue);
        unlock_interrupts();

        if(p != NULL)
        {
            LINK_STATS_INC(link.recv);

            /* Update SNMP stats (only if you use SNMP) */
            MIB2_STATS_NETIF_ADD(netif, ifinoctets, p->tot_len);
            int unicast = ((p->payload[0] & 0x01) == 0);
            if (unicast)
            {
                MIB2_STATS_NETIF_INC(netif, ifinucastpkts);
            }
            else
            {
                MIB2_STATS_NETIF_INC(netif, ifinnucastpkts);
            }

            if(netif.input(p, &netif) != ERR_OK)
            {
                pbuf_free(p);
            }
        }

        /* Cyclic lwIP timers check */
        sys_check_timeouts();

        /* your application goes here */
    }
}
